<?php
/**
 * Created by 无所谓已
 * User: Administrator
 * Date: 2025-08-17
 * Time: 16:08
 */

namespace plugin\csauto\app\utils;

class QBittorrentClient
{
    private $baseUrl;
    private $cookieFile;
    private $isLoggedIn = false;


//try {
//    // 初始化客户端
//$qb = new QBittorrentClient('http://localhost', 8080, 'admin', 'adminadmin');
//
//    // 获取版本信息
//echo "qBittorrent 版本: " . $qb->getVersion() . "\n";
//echo "API 版本: " . $qb->getApiVersion() . "\n";
//echo "默认保存路径: " . $qb->getDefaultSavePath() . "\n\n";
//
//    // 获取当前 torrents 列表
//$torrents = $qb->getTorrents([
//'filter' => 'all',  // all, downloading, seeding, completed, paused, active, inactive
//'sort' => 'name'
//]);
//
//echo "当前有 " . count($torrents) . " 个 torrents:\n";
//foreach ($torrents as $torrent) {
//echo " - " . $torrent['name'] . " (" . formatSize($torrent['total_size']) . ") - " .
//round($torrent['progress'] * 100, 2) . "% " . $torrent['state'] . "\n";
//}
//
//// 添加新的 torrent (示例)
//// $qb->addTorrentByUrl('magnet:?xt=urn:btih:EXAMPLE');
//
//// 创建分类
//// $qb->createCategory('Movies', '/downloads/Movies');
//
//// 设置全局限速
//// $qb->setGlobalDownloadLimit(1024*1024); // 1MB/s
//// $qb->setGlobalUploadLimit(512*1024);    // 512KB/s
//
//} catch (Exception $e) {
//    echo "错误: " . $e->getMessage() . "\n";
//}


    public function __construct($host, $port = 8080, $username = 'admin', $password = 'adminadmin')
    {
        $this->baseUrl = rtrim($host, '/') . ':' . $port;
        if (strpos($host, 'http') === false) {
            $this->baseUrl = 'http://' . $this->baseUrl;
        }

        $this->cookieFile = tempnam(sys_get_temp_dir(), 'qbittorrent');
        $this->login($username, $password);
    }

    /**
     * 用户登录认证
     */
    public function login($username, $password)
    {
        $url = $this->baseUrl . '/api/v2/auth/login';
        $data = [
            'username' => $username,
            'password' => $password
        ];

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_COOKIEJAR, $this->cookieFile);
        curl_setopt($ch, CURLOPT_HEADER, true);

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($httpCode === 200 && strpos($response, 'Ok.') !== false) {
            $this->isLoggedIn = true;
            return true;
        }

        throw new \Exception('登录失败: ' . $response);
    }

    /**
     * 用户登出
     */
    public function logout()
    {
        $url = $this->baseUrl . '/api/v2/auth/logout';
        $response = $this->makeRequest($url, 'POST');

        if ($response === 'Ok.') {
            $this->isLoggedIn = false;
            return true;
        }

        return false;
    }

    /**
     * 发送 HTTP 请求
     */
    private function makeRequest($url, $method = 'GET', $data = null)
    {
        if (!$this->isLoggedIn) {
            throw new Exception('未登录到 qBittorrent');
        }

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_COOKIEFILE, $this->cookieFile);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

        if ($method === 'POST') {
            curl_setopt($ch, CURLOPT_POST, true);
            if ($data) {
                curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
            }
        }

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($httpCode >= 400) {
            throw new Exception("HTTP 错误: {$httpCode}", $httpCode);
        }
//        addlog('qb-log', $response);
        return $response;
    }

    /**
     * 获取应用版本信息
     */
    public function getVersion()
    {
        $url = $this->baseUrl . '/api/v2/app/version';
        return $this->makeRequest($url);
    }

    /**
     * 获取 API 版本
     */
    public function getApiVersion()
    {
        $url = $this->baseUrl . '/api/v2/app/webapiVersion';
        return $this->makeRequest($url);
    }

    /**
     * 获取应用默认保存路径
     */
    public function getDefaultSavePath()
    {
        $url = $this->baseUrl . '/api/v2/app/defaultSavePath';
        return $this->makeRequest($url);
    }

    /**
     * 获取所有 torrents 信息
     */
    public function getTorrents($options = [])
    {
        $url = $this->baseUrl . '/api/v2/torrents/info';

        if (!empty($options)) {
            $url .= '?' . http_build_query($options);
        }

        $response = $this->makeRequest($url);
        return json_decode($response, true);
    }

    /**
     * 获取特定 torrent 的属性
     */
    public function getTorrentProperties($hash)
    {
        $url = $this->baseUrl . '/api/v2/torrents/properties?hash=' . urlencode($hash);
        $response = $this->makeRequest($url);
        return json_decode($response, true);
    }

    /**
     * 获取 torrent trackers 信息
     */
    public function getTorrentTrackers($hash)
    {
        $url = $this->baseUrl . '/api/v2/torrents/trackers?hash=' . urlencode($hash);
        $response = $this->makeRequest($url);
        return json_decode($response, true);
    }

    /**
     * 获取 torrent 文件列表
     */
    public function getTorrentFiles($hash)
    {
        $url = $this->baseUrl . '/api/v2/torrents/files?hash=' . urlencode($hash);
        $response = $this->makeRequest($url);
        return json_decode($response, true);
    }

    /**
     * 添加 torrent (磁力链接或URL)
     * 
     * @param string|array $urls
     * @param string $savePath
     * @param string $category
     * @param array $tags
     * @param array $options
     * @return bool
     */
    public function addTorrentByUrl($urls, $savePath = '', $category = '', $tags = [], $options = [])
    {
        $url = $this->baseUrl . '/api/v2/torrents/add';

        $data = array_merge([
            'urls' => is_array($urls) ? implode("\n", $urls) : $urls,
            'savepath' => $savePath,
            'category' => $category,
            'tags' => is_array($tags) ? implode(',', $tags) : $tags
        ], $options);

        $response = $this->makeRequest($url, 'POST', $data);
        // 根据 qBittorrent WebUI API 规范，成功返回 "Ok."
        return $response === 'Ok.';
    }

    /**
     * 通过文件上传 torrent
     *
     * @param        $filePath
     * @param string $savePath
     * @param string $category
     * @param array  $tags
     * @param array  $options
     * @return bool|array 返回 true 表示成功，false 表示失败，数组表示详细结果
     */
    public function addTorrentByFile($filePath, $savePath = '', $category = '', $tags = [], $options = [])
    {
        $url = $this->baseUrl . '/api/v2/torrents/add';

        // 先获取种子的 hash 值
        $torrentHash = null;
        try {
            $torrentHash = $this->calculateTorrentHash($filePath);
        } catch (\Exception $e) {
            // 如果无法计算 hash，继续尝试添加
        }

        // 如果能计算出 hash，检查种子是否已存在
        if ($torrentHash) {
            try {
                $existingTorrents = $this->getTorrents();
                foreach ($existingTorrents as $torrent) {
                    if (strtolower($torrent['hash']) === strtolower($torrentHash)) {
                        // 种子已存在，根据用户需求，认为这是成功的
                        return true;
                    }
                }
            } catch (\Exception $e) {
                // 检查失败，继续尝试添加
            }
        }

        $data = array_merge([
            'torrents' => new \CURLFile($filePath),
            'savepath' => $savePath,
            'category' => $category,
            'tags' => is_array($tags) ? implode(',', $tags) : $tags
        ], $options);

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_COOKIEFILE, $this->cookieFile);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HEADER, false);

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        // 根据 qBittorrent WebUI API 规范判断：
        // - HTTP 200 且响应为 "Ok." 表示成功
        // - 如果响应为 "Fails."，可能是种子已存在，也认为成功
        if ($httpCode === 200) {
            if ($response === 'Ok.') {
                return true;
            }
            // 如果返回 "Fails."，再次检查种子是否已存在
            if ($response === 'Fails.' && $torrentHash) {
                try {
                    $existingTorrents = $this->getTorrents();
                    foreach ($existingTorrents as $torrent) {
                        if (strtolower($torrent['hash']) === strtolower($torrentHash)) {
                            // 种子已存在，认为添加成功
                            return true;
                        }
                    }
                } catch (\Exception $e) {
                    // 检查失败
                }
            }
        }

        return false;
    }

    /**
     * 计算种子文件的 info hash
     *
     * @param string $filePath
     * @return string|null
     */
    private function calculateTorrentHash($filePath)
    {
        if (!file_exists($filePath)) {
            return null;
        }

        try {
            // 使用项目中已有的 calculateTorrentHashWithBencode 函数
            return strtolower(calculateTorrentHashWithBencode($filePath));
        } catch (\Exception $e) {
            return null;
        }
    }

    /**
     * 暂停 torrent
     */
    public function pauseTorrent($hashes)
    {
        $url = $this->baseUrl . '/api/v2/torrents/pause';
        $hashes = is_array($hashes) ? implode('|', $hashes) : $hashes;

        $data = ['hashes' => $hashes];
        $response = $this->makeRequest($url, 'POST', $data);

        return $response === 'Ok.';
    }

    /**
     * 恢复 torrent
     */
    public function resumeTorrent($hashes)
    {
        $url = $this->baseUrl . '/api/v2/torrents/resume';
        $hashes = is_array($hashes) ? implode('|', $hashes) : $hashes;

        $data = ['hashes' => $hashes];
        $response = $this->makeRequest($url, 'POST', $data);

        return $response === 'Ok.';
    }

    /**
     * 删除 torrent
     * 
     * @param string|array $hashes
     * @param bool $deleteFiles
     * @return bool
     */
    public function deleteTorrent($hashes, $deleteFiles = false)
    {
        $hashArray = is_array($hashes) ? $hashes : [$hashes];
        
        // 先检查种子是否存在
        try {
            $existingTorrents = $this->getTorrents();
            $existingHashes = array_map(function($torrent) {
                return strtolower($torrent['hash']);
            }, $existingTorrents);
            
            $allNotExist = true;
            foreach ($hashArray as $hash) {
                if (in_array(strtolower($hash), $existingHashes)) {
                    $allNotExist = false;
                    break;
                }
            }
            
            // 如果所有要删除的种子都不存在，认为删除目标已达成
            if ($allNotExist) {
                return true;
            }
        } catch (\Exception $e) {
            // 检查失败，继续尝试删除
        }
        
        $url = $this->baseUrl . '/api/v2/torrents/delete';
        $hashesStr = is_array($hashes) ? implode('|', $hashes) : $hashes;

        $data = [
            'hashes' => $hashesStr,
            'deleteFiles' => $deleteFiles ? 'true' : 'false'
        ];

        try {
            $response = $this->makeRequest($url, 'POST', $data);
            
            // 根据 qBittorrent WebUI API 规范，成功返回 "Ok."
            if ($response === 'Ok.') {
                return true;
            }
            
            // 如果返回失败，再次检查种子是否已不存在
            $existingTorrents = $this->getTorrents();
            $existingHashes = array_map(function($torrent) {
                return strtolower($torrent['hash']);
            }, $existingTorrents);
            
            $allDeleted = true;
            foreach ($hashArray as $hash) {
                if (in_array(strtolower($hash), $existingHashes)) {
                    $allDeleted = false;
                    break;
                }
            }
            
            // 如果种子已经不存在了，认为删除成功（目标达成）
            return $allDeleted;
            
        } catch (\Exception $e) {
            // 删除失败，再次检查种子是否还存在
            try {
                $existingTorrents = $this->getTorrents();
                $existingHashes = array_map(function($torrent) {
                    return strtolower($torrent['hash']);
                }, $existingTorrents);
                
                $allDeleted = true;
                foreach ($hashArray as $hash) {
                    if (in_array(strtolower($hash), $existingHashes)) {
                        $allDeleted = false;
                        break;
                    }
                }
                
                // 如果种子已经不存在了，认为删除成功（目标达成）
                return $allDeleted;
            } catch (\Exception $e2) {
                // 无法验证，返回失败
                return false;
            }
        }
    }

    /**
     * 重新检查 torrent
     */
    public function recheckTorrent($hashes)
    {
        $url = $this->baseUrl . '/api/v2/torrents/recheck';
        $hashes = is_array($hashes) ? implode('|', $hashes) : $hashes;

        $data = ['hashes' => $hashes];
        $response = $this->makeRequest($url, 'POST', $data);

        return $response === 'Ok.';
    }

    /**
     * 设置 torrent 分类
     */
    public function setTorrentCategory($hashes, $category)
    {
        $url = $this->baseUrl . '/api/v2/torrents/setCategory';
        $hashes = is_array($hashes) ? implode('|', $hashes) : $hashes;

        $data = [
            'hashes' => $hashes,
            'category' => $category
        ];

        $response = $this->makeRequest($url, 'POST', $data);
        return $response === 'Ok.';
    }

    /**
     * 创建分类
     */
    public function createCategory($category, $savePath = '')
    {
        $url = $this->baseUrl . '/api/v2/torrents/createCategory';

        $data = [
            'category' => $category,
            'savePath' => $savePath
        ];

        $response = $this->makeRequest($url, 'POST', $data);
        return $response === 'Ok.';
    }

    /**
     * 获取所有分类
     */
    public function getCategories()
    {
        $url = $this->baseUrl . '/api/v2/torrents/categories';
        $response = $this->makeRequest($url);
        return json_decode($response, true);
    }

    /**
     * 设置下载限速 (bytes/s)
     */
    public function setDownloadLimit($hashes, $limit)
    {
        $url = $this->baseUrl . '/api/v2/torrents/setDownloadLimit';
        $hashes = is_array($hashes) ? implode('|', $hashes) : $hashes;

        $data = [
            'hashes' => $hashes,
            'limit' => $limit
        ];

        $response = $this->makeRequest($url, 'POST', $data);
        return $response === 'Ok.';
    }

    /**
     * 设置上传限速 (bytes/s)
     */
    public function setUploadLimit($hashes, $limit)
    {
        $url = $this->baseUrl . '/api/v2/torrents/setUploadLimit';
        $hashes = is_array($hashes) ? implode('|', $hashes) : $hashes;

        $data = [
            'hashes' => $hashes,
            'limit' => $limit
        ];

        $response = $this->makeRequest($url, 'POST', $data);
        return $response === 'Ok.';
    }

    /**
     * 获取全局下载限速
     */
    public function getGlobalDownloadLimit()
    {
        $url = $this->baseUrl . '/api/v2/transfer/downloadLimit';
        $response = $this->makeRequest($url);
        return (int)$response;
    }

    /**
     * 获取全局上传限速
     */
    public function getGlobalUploadLimit()
    {
        $url = $this->baseUrl . '/api/v2/transfer/uploadLimit';
        $response = $this->makeRequest($url);
        return (int)$response;
    }

    /**
     * 设置全局下载限速
     */
    public function setGlobalDownloadLimit($limit)
    {
        $url = $this->baseUrl . '/api/v2/transfer/setDownloadLimit';
        $data = ['limit' => $limit];
        $response = $this->makeRequest($url, 'POST', $data);
        return $response === 'Ok.';
    }

    /**
     * 设置全局上传限速
     */
    public function setGlobalUploadLimit($limit)
    {
        $url = $this->baseUrl . '/api/v2/transfer/setUploadLimit';
        $data = ['limit' => $limit];
        $response = $this->makeRequest($url, 'POST', $data);
        return $response === 'Ok.';
    }

    /**
     * 设置超级做种模式
     */
    public function setSuperSeeding($hashes, $value)
    {
        $url = $this->baseUrl . '/api/v2/torrents/setSuperSeeding';
        $data = ['hashes' => $hashes, 'value' => $value];
        $response = $this->makeRequest($url, 'POST', $data);
        return $response === 'Ok.';
    }

    /**
     * 析构函数，清理临时文件
     */
    public function __destruct()
    {
        if (file_exists($this->cookieFile)) {
            unlink($this->cookieFile);
        }
    }
}